package com.edu.app.service.impl.wechat;

import com.edu.app.exception.wechat.NotSupportHttpImpl;
import com.edu.app.exception.wechat.NotSupportStoreImpl;
import com.edu.app.model.wechat.WechatConfig;
import com.edu.app.model.wechat.WxError;
import com.edu.app.model.wechat.WxErrorException;
import com.edu.app.service.sys.wechat.WeChatServiceExecutor;
import com.edu.app.service.sys.wechat.WechatAccessTokenService;
import com.edu.app.util.http.DataType;
import com.edu.app.util.http.HttpImplConfig;
import com.edu.app.util.http.HttpInterface;
import com.edu.app.util.http.HttpUtils;
import com.edu.app.util.http.exception.NotSupportDataTypeException;


import java.io.IOException;

import java.util.Map;


public class WeChatServiceExecutorImpl implements WeChatServiceExecutor {

    protected HttpImplConfig httpImplConfig;


    private WechatConfig wechatConfig;

    public WeChatServiceExecutorImpl(HttpImplConfig httpImplConfig,WechatConfig wechatConfig)
    {
        accessTokenService   = new WeChatAccessTokenServiceImpl(httpImplConfig,wechatConfig);
    }

    private WechatAccessTokenService accessTokenService;

    public WechatAccessTokenService getAccessTokenService() {
        return accessTokenService;
    }

    public void setAccessTokenService(WechatAccessTokenService accessTokenService) {
        this.accessTokenService = accessTokenService;
    }

    /**
     * 向微信端发送请求，在这里执行的策略是当发生access_token过期时才去刷新，然后重新执行请求，而不是全局定时请求.
     */

    public String execute(String url,Map<String,Object> params,ExecutorType type,DataType dataType) throws WxErrorException {
        int retryTimes = 0;
        do {
            try {
                return this.executeInternal(url, params, type,dataType);
            } catch (WxErrorException e) {
                if (retryTimes + 1 > 10) {
                    //this.log.warn("重试达到最大次数【{}】", maxRetryTimes);
                    //最后一次重试失败后，直接抛出异常，不再等待
                    throw new RuntimeException("微信服务端异常，超出重试次数");
                }

                WxError error = e.getError();
                // -1 系统繁忙, 1000ms后重试
                if (error.getErrcode() == -1) {
                    int sleepMillis = 10;//this.retrySleepMillis * (1 << retryTimes);
                    try {
                        //this.log.warn("微信系统繁忙，{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
                        Thread.sleep(sleepMillis);
                    } catch (InterruptedException e1) {
                        throw new RuntimeException(e1);
                    }
                } else {
                    throw e;
                }
            }
        } while (retryTimes++ < 10); //this.maxRetryTimes);

        //this.log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
        throw new RuntimeException("微信服务端异常，超出重试次数");
    }


    private String executeInternal(String url,Map<String,Object> params,ExecutorType type,DataType dataType) throws WxErrorException{

        String response = "";
        try {
            String accessToken = getAccessToken(false);


            HttpInterface httpInterface = HttpUtils.GetHttpInterface(httpImplConfig);

            switch(type){
                case POSTSYNC:
                    String urlwithtoken = String.format(url,
                            accessToken);
                    response = httpInterface.HttpPost(urlwithtoken, params, dataType, "");
                    break;
                case GETSYNC:
                    params.put("access_token", accessToken);
                    response = httpInterface.HttpGetSync(url, params);
                    break;
            }

            WxError error = WxError.fromJson(response);
            if(error.getErrcode() != 1) {
                if (error.getErrcode() == 42001 || error.getErrcode() == 40001 || error.getErrcode() == 40014) {
                    // 强制设置wxMpConfigStorage它的access token过期了，这样在下一次请求里就会刷新access token
                    accessTokenService.getAccessTokenStorage().expireAccessToken();
                    if (accessTokenService.getAccessTokenStorage().autoRefreshToken()) {
                        return this.execute(url, params, type, dataType);
                    }

                }

                if (error.getErrcode() != 0) {
                    //this.log.error("\n【请求地址】: {}\n【请求参数】：{}\n【错误信息】：{}", uriWithAccessToken, dataForLog, error);
                    throw new WxErrorException(error);
                }
            }

        }
        catch(NotSupportHttpImpl e){

        }
        catch(IOException ioe){

        }
        catch(NotSupportDataTypeException e){

        }
        catch(NotSupportStoreImpl e){

        }
        return response;
    }


    private String getAccessToken(boolean forceRefresh) throws NotSupportStoreImpl,WxErrorException{

        return accessTokenService.getAccessToken(forceRefresh);

    }


}
